package com.pt25.study.example.interfaces.facade.test;


import com.pt25.base.dep.redis.RedisLocalCacheService;
import com.pt25.base.dep.redis.RedisService;
import com.pt25.base.dep.redis.aspect.ClearCache;
import com.pt25.base.dep.redis.aspect.QueryCache;
import com.pt25.base.dep.redis.aspect.SaveCache;
import com.pt25.base.model.common.constants.RedisConstant;
import com.pt25.base.res.ResBody;
import com.pt25.base.util.JsonUtil;
import com.pt25.study.example.interfaces.vo.RedisCacheTestVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.*;

import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@EnableScheduling
@Slf4j
@Tag(name = "redis test api")
@RefreshScope
@RestController
@RequestMapping("/test-api/example")
public class RedisTestController {

    private final static String TEST_REDIS = "/test-redis";
    private final static String SAVE_CACHE = "/save-cache";
    private final static String QUERY_CACHE = "/query-cache";
    private final static String CLEAR_CACHE = "/clear-cache";

    @Resource
    private RedisService redisService;

    @Resource
    private RedisLocalCacheService redisLocalCacheService;


    @Operation(summary = "测试redis功能")
    @GetMapping(TEST_REDIS)
    public String testRedis() {

        RedissonClient cluster1 = redisService.getRedissonClient(RedisConstant.CLUSTER1);
        RedissonClient single1 = redisService.getRedissonClient(RedisConstant.SINGLE1);
        //RedissonClient defaultRedis = redissonService.getRedissonClient();

        cluster1.getBucket("test_data", new StringCodec()).set("test1");
        Object obj1 = cluster1.getBucket("test_data", new StringCodec()).get();
        cluster1.getBucket("test_data", new StringCodec()).delete();

        single1.getBucket("test_data", new StringCodec()).set("test2");
        Object obj2 = single1.getBucket("test_data", new StringCodec()).get();
        single1.getBucket("test_data", new StringCodec()).delete();


        Long id = redisService.genAutoIncrID(RedisConstant.CLUSTER1, "hzc_gen_id_test");

        return "obj1:" + obj1 + ",obj2:" + obj2 + " ,id：" + id;
    }


    @SaveCache(redisName = RedisConstant.CLUSTER1, cacheKey = "redisCacheTestVO.id")
    @Operation(summary = "save-cache")
    @PostMapping(SAVE_CACHE)
    public RedisCacheTestVo saveCache(@RequestBody RedisCacheTestVo redisCacheTestVO, @RequestParam(required = false) Integer id) {
        log.info("id={}", id);
        return redisCacheTestVO;
    }

    @QueryCache(redisName = RedisConstant.CLUSTER1, cacheKey = "id")
    @Operation(summary = "query-cache")
    @GetMapping(QUERY_CACHE)
    public ResBody queryCache(Long id) {
        log.info("id={}", id);
        return ResBody.builder().build().ok();
    }


    @ClearCache(value = RedisCacheTestVo.class, redisName = RedisConstant.CLUSTER1, cacheKey = "redisCacheTestVO.id")
    @Operation(summary = "clear-cache")
    @DeleteMapping(CLEAR_CACHE)
    public void clearCache(@RequestBody RedisCacheTestVo redisCacheTestVO) {
        log.info("redisCacheTestVO={}", JsonUtil.toJson(redisCacheTestVO));
    }


    @Operation(summary = "save-local-cache")
    @PostMapping(SAVE_CACHE + "-1")
    public ResBody saveCache() {
        redisService.getRedissonClient(RedisConstant.SINGLE1).getBucket("hzc_test_str", new StringCodec()).set("hzc");
        redisService.getRedissonClient(RedisConstant.SINGLE1).getBucket("hzc_test_str", new StringCodec()).expire(Duration.ofMinutes(10));

        redisService.getRedissonClient(RedisConstant.SINGLE1).getBucket("hzc_test_str1", new StringCodec()).set("hzc");
        redisService.getRedissonClient(RedisConstant.SINGLE1).getBucket("hzc_test_str1", new StringCodec()).expire(Duration.ofMinutes(10));

        redisService.getRedissonClient().getMap("hzc_test_map", new StringCodec()).put("name", "hzc");
        redisService.getRedissonClient().getMap("hzc_test_map", new StringCodec()).expire(Duration.ofMinutes(10));

        redisService.getRedissonClient().getSet("hzc_test_set", new StringCodec()).add("one");
        redisService.getRedissonClient().getSet("hzc_test_set", new StringCodec()).add("two");
        redisService.getRedissonClient().getSet("hzc_test_set", new StringCodec()).expire(Duration.ofMinutes(10));


        redisService.getRedissonClient().getList("hzc_test_list", new StringCodec()).add("one1");
        redisService.getRedissonClient().getList("hzc_test_list", new StringCodec()).add("two2");
        redisService.getRedissonClient().getList("hzc_test_list", new StringCodec()).expire(Duration.ofMinutes(10));

        return ResBody.builder().build().ok();
    }


    @Operation(summary = "query-local-cache")
    @PostMapping(QUERY_CACHE + "-1")
    public ResBody queryCache() {
        Object data = redisLocalCacheService.getStrLocalCache(RedisConstant.SINGLE1, "hzc_test_str");
        Map<Object, Object> hzcTestMap = redisLocalCacheService.getMapLocalCache("hzc_test_map");
        Object mapDataLocalCache = redisLocalCacheService.getMapDataLocalCache("hzc_test_map", "name");
        Set<Object> hzcTestSet = redisLocalCacheService.getSetLocalCache("hzc_test_set");
        List<Object> hzcTestList = redisLocalCacheService.getListLocalCache("hzc_test_list");
        return ResBody.builder().build().ok("");
    }

    @Scheduled(cron = "*/30 * * * * *")
    public void testUnblockLock1() {
        if (redisService.unblockLock(RedisConstant.SINGLE1, "hzc_test_str")) {
            log.info("testUnblockLock1");
        }
    }

    @Scheduled(cron = "*/30 * * * * *")
    public void testUnblockLock2() {
        if (redisService.unblockLock(RedisConstant.SINGLE1, "hzc_test_str")) {
            log.info("testUnblockLock2");
        }
    }

    @Scheduled(cron = "*/30 * * * * *")
    public void testUnblockLock3() {
        RLock lock = redisService.getRedissonClient().getLock("scheduledTaskLock");
        try {
            if (lock.tryLock(0, 30, TimeUnit.SECONDS)) {
                // 获取锁成功，执行业务逻辑
                System.out.println("执行定时任务3: " + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    @Scheduled(cron = "*/30 * * * * *")
    public void testUnblockLock4() {
        RLock lock = redisService.getRedissonClient().getLock("scheduledTaskLock");
        try {
            if (lock.tryLock(0, 30, TimeUnit.SECONDS)) {
                // 获取锁成功，执行业务逻辑
                System.out.println("执行定时任务4: " + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
